﻿using Microsoft.VisualStudio.TestTools.UnitTesting;
using MongoDB.Driver;
using Sustainalytics.BusinessResearchProductStates.Entities.ResearchState;
using Sustainalytics.ClientDW.Entities;
using Sustainalytics.DataLayer.PI;
using Sustainalytics.Entities.ProductInvolvement;
using Sustainalytics.MongoDB.Extensions;
using System;
using System.Collections.Generic;
using System.Linq;
using static Sustainalytics.Utils.AssessementList;

namespace Sustainalytics.DataLayer.Tests.PI
{
    [TestClass]
    public class CompanyAssessmentShortReportRepositoryTests
    {
        private IPICompanyAssessmentRepository _rep;
        private string dbCnxPI = "mongodb://localhost:27017/ProductinvolvementDWTests";
        private string dbCnxClient = "mongodb://localhost:27017/ClientDWTests";
        private string databaseName = "ClientDWTests";
        private IMongoDatabase database = null;
        private List<PICompanyAssessmentShortReport> companyAssessmentsShortReportList;

        [TestInitialize]
        public void Initialize()
        {
            var mongoClient = new MongoClient(dbCnxPI);
            database = mongoClient.GetDatabase(databaseName);

            database.CreateCollection("PICompanyAssessmentShortReport");
            var companyAssessmentShortReportCollection = database.GetCollection<PICompanyAssessmentShortReport>();

            companyAssessmentsShortReportList = new List<PICompanyAssessmentShortReport>();
            PopulateCompanyAssessmentShortReportCollection();

            companyAssessmentShortReportCollection.InsertMany(companyAssessmentsShortReportList);
            _rep = new PICompanyAssessmentRepository(dbCnxPI, dbCnxClient);
        }

        #region test data

        private void PopulateCompanyAssessmentShortReportCollection()
        {
            companyAssessmentsShortReportList.AddRange(
                new List<PICompanyAssessmentShortReport>()
                {
                    new PICompanyAssessmentShortReport()
                    {
                        Id = Guid.Parse("e0cfbb53-a2ea-4f7c-be53-1d543a8154b8"),
                        CompanyNameLowerCase = "sabic capital i b.v.",
                        Exchange = null,
                        Ticker=  null,
                        Industry = "Chemicals",
                        PeerGroupName = "Chemicals",
                        IndicatorSymbol = "AT",
                        IndicatorSymbolDescription = "Animal Testing",
                        CategorySymbol = "AT6",
                        CategoryOfInvolvementDescription = "Based on the company’s activities and products, the company is likely to be involved in animal testing for non-pharmaceutical products.",
                        RangeOwnership = "N/A"
                    },
                    new PICompanyAssessmentShortReport()
                    {
                        Id = Guid.Parse("e58139fe-834b-4d7e-bf22-d9a82f07cfd1"),
                        CompanyNameLowerCase = "empresas cablevision, s.a.b. de c.v.",
                        Exchange = "BMV",
                        Ticker=  "CABLE CPO",
                        Industry = "Media",
                        PeerGroupName = "Media",
                        IndicatorSymbol = "AE",
                        IndicatorSymbolDescription = "Adult Entertainment",
                        CategorySymbol = "AE3",
                        CategoryOfInvolvementDescription = "The company is involved in the distribution of adult entertainment materials.",
                        RangeOwnership = "0-4.9%"
                    },
                    new PICompanyAssessmentShortReport()
                    {
                        Id = Guid.Parse("546cc107-b607-48d6-8688-1ce4bfc7a068"),
                        CompanyNameLowerCase = "mti computers and software services (1982) ltd.",
                        Exchange = "TASE",
                        Ticker =  "MTCO",
                        Industry = "Communications Equipment",
                        PeerGroupName = "Technology Hardware",
                        IndicatorSymbol = "MC",
                        IndicatorSymbolDescription = "Military Contracting",
                        CategorySymbol = "MC5",
                        CategoryOfInvolvementDescription = "The company provides non-weapons related tailor-made products and/or services to the military or defence industry.",
                        RangeOwnership = "10-24.9%"
                    },
                    new PICompanyAssessmentShortReport()
                    {
                        Id = Guid.Parse("70350355-d806-4ca4-b69b-e200f98d05c6"),
                        CompanyNameLowerCase = "rsl electronics ltd.",
                        Exchange = "TASE",
                        Ticker=  "RSEL",
                        Industry = "Aerospace & Defense",
                        PeerGroupName = "Aerospace & Defense",
                        IndicatorSymbol = "MC",
                        IndicatorSymbolDescription = "Military Contracting",
                        CategorySymbol = "MC3",
                        CategoryOfInvolvementDescription = "The company provides tailor-made products and/or services that support military weapons.",
                        RangeOwnership = "50-100%"
                    },
                    new PICompanyAssessmentShortReport()
                    {
                        Id = Guid.Parse("77b1a36f-7b66-4510-bc0e-8a4f960b4735"),
                        CompanyNameLowerCase = "lotto24 ag",
                        Exchange = "DB",
                        Ticker=  "LO24",
                        Industry = "Hotels, Restaurants & Leisure",
                        PeerGroupName = "Consumer Services",
                        IndicatorSymbol = "GB",
                        IndicatorSymbolDescription = "Gambling",
                        CategorySymbol = "GB5",
                        CategoryOfInvolvementDescription = "The company provides supporting products/services to gambling operations.",
                        RangeOwnership = "50-100%"
                    }
                });
        }

        #endregion

        [TestCleanup]
        public void Cleanup()
        {
            var mongoClient = new MongoClient(dbCnxPI);
            mongoClient.DropDatabase(databaseName);
        }

        [TestMethod]
        public void CompanyAssessmentShortRepository_ReadCount_FilterByCompanyName_Industry()
        {
            List<int> expectedUniverses = new List<int>() { 20 };
            List<string> claimedIndicators = new List<string>() { "AT", "AE", "MC", "GB" };

            PIAssessmentListFilters filters = new PIAssessmentListFilters()
            {
                CompanyNameLowerCase = "cablevision",
                Industry = "media",
                PiIndicatorSymbolsStrFilter = null,
                PiRangeOwnershipStrFilter = null
            };

            var companyIds = getCompanyIds(expectedUniverses);

            List<PICompanyAssessmentShortReport> expectedCollection = companyAssessmentsShortReportList.Where(
               el => el.CompanyNameLowerCase.Contains(filters.CompanyNameLowerCase)
               && el.PeerGroupName.ToLowerInvariant().Contains(filters.Industry.ToLowerInvariant())
               && companyIds.Contains(el.CompanyId)).ToList();

            int expectedCount = expectedCollection.Count;

            long actualCount = _rep.ReadCount(filters, expectedUniverses, claimedIndicators);
            List<CompanyList> actualCollection = _rep.Read(filters, expectedUniverses, claimedIndicators, null, null, null, true).ToList();

            Assert.IsTrue(expectedCount == actualCount, "Returned value is not the same as expected.");
            Assert.IsTrue(expectedCollection.Select(el => el.Id).SequenceEqual(actualCollection.Select(el => el.Id)));
        }

        [TestMethod]
        public void CompanyAssessmentShortRepository_ReadCount_FilterBy_PIIndicator()
        {
            List<int> expectedUniverses = new List<int>() { 20 };
            List<string> claimedIndicators = new List<string>() { "AT", "AE", "MC", "GB" };

            PIAssessmentListFilters filters = new PIAssessmentListFilters()
            {
                CompanyNameLowerCase = null,
                Industry = null,
                PiIndicatorSymbolsStrFilter = "AE|MC",
                PiRangeOwnershipStrFilter = ""
            };

            var indArr = filters.PiIndicatorSymbolsStrFilter.Split('|');
            var roArr = filters.PiRangeOwnershipStrFilter.Split('|');

            var companyIds = getCompanyIds(expectedUniverses);

            IEnumerable<PICompanyAssessmentShortReport> expectedCollection = companyAssessmentsShortReportList.Where(el =>
                  companyIds.Contains(el.CompanyId));

            if (indArr.Any(x => !string.IsNullOrEmpty(x)))
            {
                expectedCollection = expectedCollection.Where(el => indArr.Contains(el.IndicatorSymbol));
            }

            if (roArr.Any(x => !string.IsNullOrEmpty(x)))
            {
                expectedCollection = expectedCollection.Where(el => roArr.Contains(el.RangeOwnership));
            }

            int expectedCount = expectedCollection.Count();

            long actualCount = _rep.ReadCount(filters, expectedUniverses, claimedIndicators);
            List<CompanyList> actualCollection = _rep.Read(filters, expectedUniverses, claimedIndicators, null, null, null, true).ToList();

            Assert.IsTrue(expectedCount == actualCount, "Returned value is not the same as expected.");
            Assert.IsTrue(expectedCollection.Select(el => el.Id).SequenceEqual(actualCollection.Select(el => el.Id)));
        }

        [TestMethod]
        public void CompanyAssessmentShortRepository_ReadCount_FilterBy_RangeOwnership()
        {
            List<int> expectedUniverses = new List<int>() { 20 };
            List<string> claimedIndicators = new List<string>() { "AT", "AE", "MC", "GB" };

            PIAssessmentListFilters filters = new PIAssessmentListFilters()
            {
                CompanyNameLowerCase = null,
                Industry = null,
                PiIndicatorSymbolsStrFilter = "",
                PiRangeOwnershipStrFilter = "10-24.9%|50-100%"
            };

            var indArr = filters.PiIndicatorSymbolsStrFilter.Split('|');
            var roArr = filters.PiRangeOwnershipStrFilter.Split('|');

            var companyIds = getCompanyIds(expectedUniverses);

            IEnumerable<PICompanyAssessmentShortReport> expectedCollection = companyAssessmentsShortReportList.Where(el =>
                      companyIds.Contains(el.CompanyId));

            if (indArr.Any(x => !string.IsNullOrEmpty(x)))
            {
                expectedCollection = expectedCollection.Where(el => indArr.Contains(el.IndicatorSymbol));
            }

            if (roArr.Any(x => !string.IsNullOrEmpty(x)))
            {
                expectedCollection = expectedCollection.Where(el => roArr.Contains(el.RangeOwnership));
            }

            int expectedCount = expectedCollection.Count();

            long actualCount = _rep.ReadCount(filters, expectedUniverses, claimedIndicators);
            List<CompanyList> actualCollection = _rep.Read(filters, expectedUniverses, claimedIndicators, null, null, null, true).ToList();

            Assert.IsTrue(expectedCount == actualCount, "Returned value is not the same as expected.");
            Assert.IsTrue(expectedCollection.Select(el => el.Id).SequenceEqual(actualCollection.Select(el => el.Id)));
        }

        [TestMethod]
        public void CompanyAssessmentShortRepository_ReadCount_FilterBy_PIIndicator_And_RangeOwnership()
        {
            List<int> expectedUniverses = new List<int>() { 20 };
            List<string> claimedIndicators = new List<string>() { "AT", "AE", "MC", "GB" };

            PIAssessmentListFilters filters = new PIAssessmentListFilters()
            {
                CompanyNameLowerCase = null,
                Industry = null,
                PiIndicatorSymbolsStrFilter = "MC",
                PiRangeOwnershipStrFilter = "10-24.9%|50-100%"
            };

            var indArr = filters.PiIndicatorSymbolsStrFilter.Split('|');
            var roArr = filters.PiRangeOwnershipStrFilter.Split('|');

            var companyIds = getCompanyIds(expectedUniverses);

            IEnumerable<PICompanyAssessmentShortReport> expectedCollection = companyAssessmentsShortReportList.Where(el =>
                      companyIds.Contains(el.CompanyId));

            if (indArr.Any(x => !string.IsNullOrEmpty(x)))
            {
                expectedCollection = expectedCollection.Where(el => indArr.Contains(el.IndicatorSymbol));
            }

            if (roArr.Any(x => !string.IsNullOrEmpty(x)))
            {
                expectedCollection = expectedCollection.Where(el => roArr.Contains(el.RangeOwnership));
            }

            int expectedCount = expectedCollection.Count();

            long actualCount = _rep.ReadCount(filters, expectedUniverses, claimedIndicators);
            List<CompanyList> actualCollection = _rep.Read(filters, expectedUniverses, claimedIndicators, null, null, null, true).ToList();

            Assert.IsTrue(expectedCount == actualCount, "Returned value is not the same as expected.");
            Assert.IsTrue(expectedCollection.Select(el => el.Id).SequenceEqual(actualCollection.Select(el => el.Id)));
        }

        public List<Guid> getCompanyIds(List<int> expectedUniverses)
        {
            return MongoFactory.GetCollectionFromDatabase<CorporateData>(MongoFactory.GetConnectionStrings().ClientDW)
                .Find(cd => cd.ResearchParentId == null
                         && cd.UniverseIds.Any(x => expectedUniverses.Contains(x))
                         && cd.ProductInvolvementResearchState.ResearchState == ResearchState.ResearchAvailable
                         && cd.ProductInvolvementResearchState.ClientFacingProducts.Contains(ClientFacingProduct.GA))
                .Project(cd => cd.Id)
                .ToList();
        }
    }
}
